{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "# @Time    : 2022/9/13 8:24\n",
    "# @Author  : 南黎\n",
    "# @FileName: 1.数据处理.py\n",
    "\n",
    "# 导包\n",
    "import numpy as np\n",
    "import pandas as pd"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "#1.读入数据\n",
    "datafile = 'boston.csv'\n",
    "data = pd.read_csv(datafile)#\n",
    "feature_names=list(data.columns) # 获取列名\n",
    "data=data.values#.values转为np数组"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "#2.数据形状变换\n",
    "# 这是数据处理的一个流程，有时候我们读取的数据是一位数组，要手动转化为二维数组，比如这题目中是对原始数据做reshape，变成N x 14的形式\n",
    "# 读入之后的数据被转化成1维array，其中array的第0-13项是第一条数据，第14-27项是第二条数据，以此类推....\n",
    "feature_num = len(feature_names)#获取列数\n",
    "\n",
    "# 我们前面读取的维度就是二维，所以我们先手动变成一维，再转回二维，模拟这个流程。\n",
    "data_error_shape=data.reshape([data.shape[0]*data.shape[1],1])# 转为不想要的维度\n",
    "data_error_shape\n",
    "data_correct_shape = data_error_shape.reshape([data_error_shape.shape[0] // feature_num, feature_num])#转为想要的维度\n",
    "data_correct_shape"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "#3.数据集划分\n",
    "#将数据集划分成训练集和测试集，其中训练集用于确定模型的参数，测试集用于评判模型的效果。\n",
    "ratio = 0.8#数据集划分比例，80%训练集 20%数据集\n",
    "offset = int(data.shape[0] * ratio) #分割比例如果有小数要取整\n",
    "training_data = data[:offset]\n",
    "training_data.shape #训练集数据\n",
    "\n",
    "test_data = data[offset:]\n",
    "test_data.shape #测试集数据\n",
    "\n",
    "#有时候也会在划分前打乱数据顺序，多次训练"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "#4.数据归一化处理\n",
    "# 对每个特征进行归一化处理，使得每个特征的取值缩放到0~1之间。这样做有两个好处：\n",
    "# 一是模型训练更高效，在后面会详细说明；\n",
    "# 二是特征前的权重大小可以代表该变量对预测结果的贡献度（因为每个特征值本身的范围相同）\n",
    "\n",
    "# 计算train数据集的最大值，最小值，平均值\n",
    "maximums, minimums, avgs = \\\n",
    "                     training_data.max(axis=0), \\\n",
    "                     training_data.min(axis=0), \\\n",
    "     training_data.sum(axis=0) / training_data.shape[0]\n",
    "\n",
    "\n",
    "ofOne_data=data.copy() #新建一个copy，避免重复运行测试时出现问题\n",
    "print(ofOne_data)\n",
    "# 对数据进行最大最小归一化处理\n",
    "for i in range(feature_num):\n",
    "    #print(maximums[i], minimums[i], avgs[i])\n",
    "    ofOne_data[:, i] = (ofOne_data[:, i] - minimums[i]) / (maximums[i] - minimums[i])\n",
    "\n",
    "print(ofOne_data)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "#5.封装成load data函数\n",
    "def load_data():\n",
    "    #1.读入数据\n",
    "    datafile = 'boston.csv'\n",
    "    data = pd.read_csv(datafile)#\n",
    "    feature_names=list(data.columns) # 获取列名\n",
    "    data=data.values#.values转为np数组\n",
    "\n",
    "    #2.数据形状变换\n",
    "    # 这是数据处理的一个流程，有时候我们读取的数据是一位数组，要手动转化为二维数组，比如这题目中是对原始数据做reshape，变成N x 14的形式\n",
    "    # 读入之后的数据被转化成1维array，其中array的第0-13项是第一条数据，第14-27项是第二条数据，以此类推....\n",
    "    feature_num = len(feature_names)#获取列数\n",
    "\n",
    "    #3.数据集划分\n",
    "    #将数据集划分成训练集和测试集，其中训练集用于确定模型的参数，测试集用于评判模型的效果。\n",
    "    ratio = 0.8#数据集划分比例，80%训练集 20%数据集\n",
    "    offset = int(data.shape[0] * ratio) #分割比例如果有小数要取整\n",
    "    training_data = data[:offset]\n",
    "    test_data = data[offset:]\n",
    "\n",
    "    #有时候也会在划分前打乱数据顺序，多次训练\n",
    "\n",
    "    #4.数据归一化处理\n",
    "    # 对每个特征进行归一化处理，使得每个特征的取值缩放到0~1之间。这样做有两个好处：\n",
    "    # 一是模型训练更高效，在后面会详细说明；\n",
    "    # 二是特征前的权重大小可以代表该变量对预测结果的贡献度（因为每个特征值本身的范围相同）\n",
    "\n",
    "    # 计算train数据集的最大值，最小值，平均值\n",
    "    maximums, minimums, avgs = \\\n",
    "                         training_data.max(axis=0), \\\n",
    "                         training_data.min(axis=0), \\\n",
    "         training_data.sum(axis=0) / training_data.shape[0]\n",
    "\n",
    "    ofOne_data=data.copy() #新建一个copy，避免重复运行测试时出现问题\n",
    "    # 对数据进行最大最小归一化处理\n",
    "    for i in range(feature_num):\n",
    "        #print(maximums[i], minimums[i], avgs[i])\n",
    "        ofOne_data[:, i] = (ofOne_data[:, i] - minimums[i]) / (maximums[i] - minimums[i])\n",
    "    print(training_data, test_data)\n",
    "    return training_data,test_data\n",
    "\n",
    "# 获取数据\n",
    "training_data,test_data = load_data()\n",
    "x = training_data[:, :-1]\n",
    "y = training_data[:, -1:]\n",
    "# 查看数据\n",
    "print(x[0])\n",
    "print(y[0])\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "#2.模型设计\n",
    "\n",
    "#如果将输入特征和输出预测值均以向量表示，输入特征xxx有13个分量，yyy有1个分量，\n",
    "# 那么参数权重的形状（shape）是13×113\\times113×1。假设我们以如下任意数字赋值参数做初始化：\n",
    "w = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, -0.1, -0.1, -0.1, -0.1, 0.1]\n",
    "w = np.array(w).reshape([13, 1])\n",
    "\n",
    "# 取出第1条样本数据，观察样本的特征向量与参数向量相乘的结果。\n",
    "x1=x[0]\n",
    "t = np.dot(x1, w)# 向量点积和矩阵乘法,\n",
    "print(t)\n",
    "\n",
    "#完整的线性回归公式，还需要初始化偏移量bbb，同样随意赋初值-0.2。那么，线性回归模型的完整输出是z=t+bz=t+bz=t+b，这个从特征和参数计算输出值的过程称为“前向计算”。\n",
    "b = -0.2\n",
    "z = t + b\n",
    "print(z)\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "# 将上述计算预测输出的过程以“类和对象”的方式来描述，类成员变量有参数www和bbb。\n",
    "# 通过写一个forward函数（代表“前向计算”）完成上述从特征和参数到输出预测值的计算过程，代码如下所示。\n",
    "class Network(object):\n",
    "    def __init__(self, num_of_weights):\n",
    "        # 随机产生w的初始值\n",
    "        # 为了保持程序每次运行结果的一致性，\n",
    "        # 此处设置固定的随机数种子\n",
    "        np.random.seed(0)\n",
    "        self.w = np.random.randn(num_of_weights, 1)\n",
    "        self.b = 0.\n",
    "\n",
    "    def forward(self, x):\n",
    "        z = np.dot(x, self.w) + self.b\n",
    "        return z\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "#基于Network类的定义，模型的计算过程如下所示。\n",
    "net = Network(13)#13个要素\n",
    "x1 = x[0]\n",
    "y1 = y[0]\n",
    "z = net.forward(x1)\n",
    "print(z)\n",
    "\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "# 3.训练配置\n",
    "# 模型设计完成后，需要通过训练配置寻找模型的最优值，即通过损失函数来衡量模型的好坏。\n",
    "# 即是损失函数求解，回归问题中，均方误差是一种比较常见的形式\n",
    "\n",
    "Loss = (y1 - z)*(y1 - z)\n",
    "print(Loss)\n",
    "\n",
    "# 因为计算损失函数时需要把每个样本的损失函数值都考虑到，所以我们需要对单个样本的损失函数进行求和，并除以样本总数NNN。"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "# 加入了损失求解的network类\n",
    "class Network(object):\n",
    "    def __init__(self, num_of_weights):\n",
    "        # 随机产生w的初始值\n",
    "        # 为了保持程序每次运行结果的一致性，此处设置固定的随机数种子\n",
    "        np.random.seed(0)\n",
    "        self.w = np.random.randn(num_of_weights, 1)\n",
    "        self.b = 0.\n",
    "\n",
    "    def forward(self, x):\n",
    "        z = np.dot(x, self.w) + self.b\n",
    "        return z\n",
    "\n",
    "    def loss(self, z, y):\n",
    "        error = z - y\n",
    "        cost = error * error\n",
    "        cost = np.mean(cost)\n",
    "        return cost"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "#使用封装的network类快速操作\n",
    "net = Network(13)\n",
    "# 此处可以一次性计算多个样本的预测值和损失函数\n",
    "x1 = x[0:3]\n",
    "y1 = y[0:3]\n",
    "z = net.forward(x1)\n",
    "print('predict: ', z)\n",
    "loss = net.loss(z, y1)\n",
    "print('loss:', loss)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from matplotlib import pyplot as plt\n",
    "\n",
    "\n",
    "#4.训练过程\n",
    "# 通过神经网络完成预测值和损失函数的计算。接下来介绍如何求解参数www和bbb的数值，这个过程也称为模型训练过程。\n",
    "# 训练过程是深度学习模型的关键要素之一，其目标是让定义的损失函数LossLossLoss尽可能的小，也就是说找到一个参数解www和bbb，使得损失函数取得极小值。\n",
    "import numpy as np\n",
    "class Network(object):\n",
    "    def __init__(self, num_of_weights):\n",
    "        # 随机产生w的初始值\n",
    "        # 为了保持程序每次运行结果的一致性，此处设置固定的随机数种子\n",
    "        np.random.seed(0)\n",
    "        self.w = np.random.randn(num_of_weights,1)\n",
    "        self.w[5] = -100.\n",
    "        self.w[9] = -100.\n",
    "        self.b = 0.\n",
    "\n",
    "    def forward(self, x):\n",
    "        z = np.dot(x, self.w) + self.b\n",
    "        return z\n",
    "\n",
    "    def loss(self, z, y):\n",
    "        error = z - y\n",
    "        num_samples = error.shape[0]\n",
    "        cost = error * error\n",
    "        cost = np.sum(cost) / num_samples\n",
    "        return cost\n",
    "\n",
    "    def gradient(self, x, y):\n",
    "        z = self.forward(x)\n",
    "        gradient_w = (z-y)*x\n",
    "        gradient_w = np.mean(gradient_w, axis=0)\n",
    "        gradient_w = gradient_w[:, np.newaxis]\n",
    "        gradient_b = (z - y)\n",
    "        gradient_b = np.mean(gradient_b)\n",
    "        return gradient_w, gradient_b\n",
    "\n",
    "    def update(self, gradient_w5, gradient_w9, eta=0.01):\n",
    "        net.w[5] = net.w[5] - eta * gradient_w5\n",
    "        net.w[9] = net.w[9] - eta * gradient_w9\n",
    "\n",
    "    def train(self, x, y, iterations=100, eta=0.01):\n",
    "        points = []\n",
    "        losses = []\n",
    "        for i in range(iterations):\n",
    "            points.append([net.w[5][0], net.w[9][0]])\n",
    "            z = self.forward(x)\n",
    "            L = self.loss(z, y)\n",
    "            gradient_w, gradient_b = self.gradient(x, y)\n",
    "            gradient_w5 = gradient_w[5][0]\n",
    "            gradient_w9 = gradient_w[9][0]\n",
    "            self.update(gradient_w5, gradient_w9, eta)\n",
    "            losses.append(L)\n",
    "            if i % 50 == 0:\n",
    "                print('iter {}, point {}, loss {}'.format(i, [net.w[5][0], net.w[9][0]], L))\n",
    "        return points, losses\n",
    "\n",
    "# 获取数据\n",
    "train_data, test_data = load_data()\n",
    "x = train_data[:, :-1]\n",
    "y = train_data[:, -1:]\n",
    "# 创建网络\n",
    "net = Network(13)\n",
    "num_iterations=2000\n",
    "# 启动训练\n",
    "points, losses = net.train(x, y, iterations=num_iterations, eta=0.01)\n",
    "\n",
    "# 画出损失函数的变化趋势\n",
    "plot_x = np.arange(num_iterations)\n",
    "plot_y = np.array(losses)\n",
    "plt.plot(plot_x, plot_y)\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}